package Checkers; 

import java.util.*;
import java.net.*;

import java.io.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class checkersGUI extends JPanel implements Runnable {

    //evo 0
    int var=50;
//    private int[] seed = {1000,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ,0,0,0,0};
//    private int[] variance = {0,var,var,var, var,var,var,var, var,var,var,var, var,var,var,var, var,var,var,var, var,var,var,var ,var,var,var,var};

    //evo 1.1
//    private int[] seed =     {100, -37, 23, -61, -3, -17, -152, 16, -5, 46, 54, 6, 40, -15, 13, -50, 6, 82, 31, 16, 69, -51, -15};
//    private int[] variance = {0, 23, 14, 20, 40, 43, 25, 37, 7, 27, 35, 26, 31, 26, 10, 22, 24, 25, 22, 7, 13, 8, 15};

    //evo 1.2
//    private int[] seed = {100, -12, 4, -60, 2, -29, -139, 1, -14, 58, 34, 18, 26, 0, 1, -64, -5, 71, 9, 3, 59, -42, -25};
//    private int[] variance = {0, 8, 11, 14, 16, 6, 8, 5, 25, 10, 5, 11, 7, 5, 13, 10, 11, 6, 8, 7, 22, 10, 17};
    //evo 1.3
//    private int[] seed = {100, -21, 0, -49, 0, -25, -129, 0, -36, 70, 47, 28, 23, 0, 0, -55, 0, 67, 21, 0, 60, -19, -13, 0, 0};
//    private int[] variance = {0, 2, 0, 7, 0, 4, 4, 0, 7, 5, 3, 4, 6, 0, 0, 6, 0, 6, 3, 0, 7, 5, 4, 10, 10};

    //evo 2.1
//    private int[] seed = {1000, 128, 0, -151, 0, -116, -87, 0, 24, 7, -105, -172, 67, 0, 0, 28, 0, 108, -212, 0, 241, 32, -62, -183, 193};
//    private int[] variance = {0, 20, 0, 22, 0, 27, 27, 0, 45, 14, 44, 29, 40, 0, 0, 31, 0, 12, 24, 0, 43, 24, 30, 20, 10};

    //evo 3.2
    private int[] seed = {1000, -455, 91, -243, 24, 69, 1, 594, 311, -274, 730, 147, 199, 374, 390, -187, 196, -75, 116, -193, 395, 37, -784, 0, 119, 264, -247, 0};
    private int[] variance = {0, 46, 47, 41, 28, 52, 22, 26, 34, 32, 14, 39, 52, 38, 27, 60, 34, 97, 29, 57, 50, 44, 43, 65, 32, 29, 9, 0};
    private GenePool gp = new GenePool(seed,variance);

    //opponent
    private int[] seed2 = {1000,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ,0,0,0,0};
    
    private int AIDEPTH = 1;

    private boolean GUI = false;
    private boolean singleGame = false;
    private final int MAXGEN = 100000;
    private int moveLimit = 150;
    private int numRounds = 1;
    private boolean scoreDraws = false;
    
    private byte[] board2=new byte[37];
    private Board board = new Board();

//    private int[] poly0 = {1000,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ,0,0,0}; //unused
    private int p1,p2;//player number, index in genepool
    private int moves = 0;
    private int generation = 0;
    private int p1Wins=0,p2Wins=0,draws=0,gameNum=0;
    
    private boolean gameOver=false; 
    private boolean endProgram=false;

    private final int w=35;
    private final int d=16;

    private boolean ai = true;
    private int player = 1;             // red, unless the server says otherwise
    private double time = 0;
    
    private JFrame checkersMainFrame = null;  //  @jve:decl-index=0:visual-constraint="27,0"
    private JPanel checkersContentPane = null;
    private JSplitPane jSplitPane = null;
    private JTable checkersTable = null;  //  @jve:decl-index=0:visual-constraint="6,363"
    private JSplitPane historySplitPane = null;
    private JButton startButton = null;
    private JScrollPane historyScrollPane = null;
    private JTextArea historyTextArea = null;
    private JTextField moveText = null;
    private JPanel panel = null;
    private SubmitListener moveListener=new SubmitListener();
    private StartListener startListener=new StartListener();
    //private ValidMoves moveChecker=new ValidMoves();

    //private MouseListener mListener=new MouseListener();
    
    /* network vars */
    private final static String user1 = "9", user2 = "10";
    private final static String pass1 = "450700", pass2 = "865958";
    private final String server = "icarus.engr.uconn.edu";
    private final int port = 3499;
    private Socket sock = null;
    private PrintWriter sockOut = null;
    private BufferedReader sockIn = null;
    
    /**
     * This method initializes checkersMainFrame    
     *  
     * @return javax.swing.JFrame   
     */
    public JFrame getCheckersMainFrame() {
        if (checkersMainFrame == null) {
            checkersMainFrame = new JFrame();
            checkersMainFrame.setMaximumSize(new Dimension(700, 350));
            checkersMainFrame.setMinimumSize(new Dimension(700, 350));
            checkersMainFrame.setResizable(false);
            checkersMainFrame.setTitle("Checkers");
            checkersMainFrame.setContentPane(getCheckersContentPane());
        }
        //contactServer("0");
        return checkersMainFrame;
    }

    /**
     * This method initializes checkersContentPane  
     *  
     * @return javax.swing.JPanel   
     */
    private JPanel getCheckersContentPane() {
        if (checkersContentPane == null) {
            checkersContentPane = new JPanel();
            checkersContentPane.setLayout(new BorderLayout());
            checkersContentPane.add(getJSplitPane(), BorderLayout.CENTER);
        }
        return checkersContentPane;
    }

    /**
     * This method initializes jSplitPane   
     *  
     * @return javax.swing.JSplitPane   
     */
    private JSplitPane getJSplitPane() {
        if (jSplitPane == null) {
            jSplitPane = new JSplitPane();
            jSplitPane.setDividerLocation(350);
            jSplitPane.setRightComponent(getHistorySplitPane());
//            jSplitPane.setLeftComponent(getCheckersTable());
            jSplitPane.setLeftComponent(this);
            this.addMouseListener(new MouseListener());
            Dimension minimumSize = new Dimension(350, 300);
            jSplitPane.getLeftComponent().setMinimumSize(minimumSize);
            jSplitPane.getRightComponent().setMinimumSize(minimumSize);
            jSplitPane.getLeftComponent().setMaximumSize(minimumSize);
            jSplitPane.getRightComponent().setMaximumSize(minimumSize);
        }
        return jSplitPane;
    }

    /**
     * This method initializes historySplitPane 
     *  
     * @return javax.swing.JSplitPane   
     */
    private JSplitPane getHistorySplitPane() {
        if (historySplitPane == null) {
            historySplitPane = new JSplitPane();
            historySplitPane.setDividerLocation(275);
            historySplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
            historySplitPane.setTopComponent(getJScrollPane());
//            historySplitPane.setRightComponent(getStartButton());
            historySplitPane.setRightComponent(getBottomPanel());
            historySplitPane.getLeftComponent().setMinimumSize(new Dimension(350, 275));
            historySplitPane.getLeftComponent().setMaximumSize(new Dimension(350, 275));
            historySplitPane.getRightComponent().setMinimumSize(new Dimension(350, 25));
            historySplitPane.getRightComponent().setMaximumSize(new Dimension(350, 25));
        }
        return historySplitPane;
    }

    /**
     * This method initializes startButton  
     *  
     * @return javax.swing.JButton  
     */
    private JButton getStartButton() {
        if (startButton == null) {
            startButton = new JButton();
            startButton.setName("startGame");
            startButton.setText("Start Game");
            startButton.setActionCommand("startGame");
            startButton.addActionListener(startListener);
        }
        return startButton;
    }

    private JPanel getBottomPanel() {
        if (panel==null)
        {
            panel=new JPanel();
        }
        if (moveText == null) {
            moveText = new JTextField("",10);
            moveText.addActionListener(moveListener);
        }
        if (startButton == null) {
            startButton = new JButton();
            startButton.setName("startGame");
            startButton.setText("Start Game");
            startButton.setActionCommand("startGame");
            startButton.addActionListener(startListener);
        }
        panel.add(startButton);
        panel.add(moveText);
        return panel;
    }
    
    /**
     * This method initializes jScrollPane  
     *  
     * @return javax.swing.JScrollPane  
     */
    private JScrollPane getJScrollPane() {
        if (historyScrollPane == null) {
            historyScrollPane = new JScrollPane();
            historyScrollPane.setViewportView(getHistoryTextArea());
        }
        return historyScrollPane;
    }

    /**
     * This method initializes historyTextArea  
     *  
     * @return javax.swing.JTextArea    
     */
    private JTextArea getHistoryTextArea() {
        if (historyTextArea == null) {
            historyTextArea = new JTextArea(10, 35);
            historyTextArea.setLineWrap(true);
            historyTextArea.setWrapStyleWord(true);
            historyTextArea.setEditable(false);
            String newline = "\n";
            historyTextArea.append("Welcome to the Group 5 Checkers Interface.  To begin " +
                    "playing checkers hit the 'Start Game' button at the bottom of the screen." +
                    "  The game history and status will be updated in this text area as the" +
                    " game progresses.  Good Luck!" + newline +newline);
        }
        return historyTextArea;
    }
    
    private void refreshBoard()
    {
        //jSplitPane.setLeftComponent(this);
        if(GUI)
            this.repaint();
    }

    public Move getBestMove(Board b) //this is where the intelligent move selection goes, currently just random.
    {
        //LinkedList<Move> allMoves=moveChecker.getMoves(board);
        LinkedList<Move> allMoves = ValidMoves.getMoves(board);
        if(allMoves.size()>0)
        {
            int pick=(int)(Math.random()*allMoves.size());
            return allMoves.get(pick);
        }
        else
        {
            return null;
        }
    }
    
    /**
     * AI Functionality
     */
    public boolean ai(int[] poly)
    {
//        System.out.println("function: ai() start");
//        refreshBoard();
//        try {Thread.currentThread().sleep(1000);} catch(Exception e) {}
//        System.out.println("board updated");
        Move m = Stratagem.getBestMove(board, AIDEPTH, -9999, 9999, poly); //-----make move here-----------
//        Move m=new Move();

        if(m!=null)
        {
            if(board.getPlayer()==1)
                executeMove("Red(CPU)",m);
            else
                executeMove("Black(CPU)",m);
            return true;
        }
        else
        {
            if(GUI)
                historyTextArea.append("No moves found by A.I.\n");
//            System.out.println("---- G A M E   O V E R ----");
            gameOver=true;
//            resetBoard();
            
            return false;
        }
    }
    
    public void resetBoard()
    {
        board = new Board();
        player = 1;             // red, unless the server says otherwise
        time = 0;
        moves = 0;
        gameOver=false;
    }
    
    public boolean randomAI() {
        Move m = getBestMove(board);
        if (m!=null) {
            executeMove("Red(CPU)", m);
            return true;
        }
        else
            historyTextArea.append("No moves found by Random A.I.\n");
        return false;
    }
    
    /**
     * Move execution
     * @param k
     */
    public void doMove(String k)
    {
//        System.out.println("function: doMove()");
        
        int x0,y0,x1,y1,xn,yn;
        x0=Integer.parseInt(k.substring(0,1));
        y0=Integer.parseInt(k.substring(1,2));
        x1=Integer.parseInt(k.substring(3,4));
        y1=Integer.parseInt(k.substring(4,5));
//            System.out.println(x0+y0+x1+y1);
        Move m=new Move(x0,y0,x1,y1);
        if(k.length()>5)
        {
            int c=6;
            while(c<k.length())
            {
                xn=Integer.parseInt(k.substring(c,c+1));
                yn=Integer.parseInt(k.substring(c+1,c+2));
                m.addCoord(xn,yn);
                c=c+3;
            }
        }
        
        String p;
        if(board.getPlayer()==1)
            p="Red";
        else
            p="Black";

//            System.out.println("Testing: ");
//            m.output();
//            moveChecker.output(board);
        //if(!moveChecker.isValid(m,board))
        if (!ValidMoves.isValid(m, board))
            historyTextArea.append("Illegal Move - Try Again.\n");
        else
        {
//                historyTextArea.append("Valid Move.\n");
            executeMove(p,m);
        }
    }
    
    /**
     * Move submission
     */
    private void submitMove()
    {
        this.repaint();
        String k=moveText.getText();

        if(k.equals("load"))
        {
            for (int i=1; i<36; i++) 
            {
                if (i==9||i==18||i==27) { board2[i] = -1; i++; }
                if (i < 14){
                }
                else if (i < 23)
                    board2[i] = 0;
            }
            board2[0] = board2[36] = -1;
            board2[13]=1;
            board2[24]=2;
            board2[25]=2;
            board2[26]=2;
            board2[29]=2;
            board = new Board(board2,(byte)1);
        }
        else if(k.length()>0 && k.charAt(0)=='d')
        {
            AIDEPTH = Integer.parseInt(""+k.substring(6));
            historyTextArea.append("Depth = "+AIDEPTH+"\n");
        }
        else if(k.equals("end"))
        {
            endProgram=true;
        }
        else if(k.equals("ai"))
        {
            ai=!ai;
            if(GUI)
                historyTextArea.append("A.I. = "+ai+"\n");
        }
        else if ((k.length()-2)%3==0 && k.length()>=5)
        {
            doMove(k);
            if(ai && board.getPlayer()==2)
            {
                refreshBoard(); //doesn't work 
                ai(seed);
            }
        }
        else
            historyTextArea.append("Invalid Input.\n");
        
        moveText.setText("");
    }
    
    private void executeMove(String p,Move m)
    {
        int jumps=board.makeMove(m);

        if(jumps!=-1)
            if(GUI)
                historyTextArea.append("<"+p+"> "+m +"  Jumps: "+jumps+"\n");
        else
            if(GUI)
                historyTextArea.append("Invalid Move - Try Again. [ERROR] \n"); //this should never happen, EVER, if it does, fix something!

            
        refreshBoard();
//        System.out.println("-Current Board Eval: "+Stratagem.evalBoard(board,poly0));
//        System.out.println("-Red King Score: "+Stratagem.kingScore(board,1));
//        System.out.println("-Black King Score: "+Stratagem.kingScore(board,2));
//        System.out.println("-Red Pawn Score: "+Stratagem.pawnScore(board,1));
//        System.out.println("-Black Pawn Score: "+Stratagem.pawnScore(board,2));
//        System.out.println("* Current Player: "+board.getPlayer());
//        Stratagem.evaluate(board,board.getPlayer());
        
//        try {Thread.currentThread().sleep(1000);} catch(Exception e) {}
        
        //moveChecker.output(board);
        //ValidMoves.output(board);
        
    }
    
    private class StartListener implements ActionListener
    {
        public void actionPerformed(ActionEvent e) {
            if ("startGame".equals(e.getActionCommand())){
                String newline = "\n";
                historyTextArea.append("Looking for game... (j/k)"+newline);
            }
        }
    }

    private class SubmitListener implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            submitMove();
        }
    }

    private class MouseListener extends MouseAdapter
    {
        public void mousePressed(MouseEvent e)
        {
            
            if(e.getButton()==1)
            {
                int x=(int)(e.getX()/w);
                int y=(int)(e.getY()/w);
                if(moveText.getText().length()==0)
                    moveText.setText(moveText.getText()+""+y+""+x);
                else
                    moveText.setText(moveText.getText()+","+y+""+x);
            }
            if(e.getButton()==3)
            {
                submitMove();
//                System.out.println("Value Red = "+board.getValue(1));
            }
        }
    }
        
    public void paintComponent(Graphics g)
    {
//        System.out.println("Painted");
        super.paintComponent (g);
        boolean col=true;
        Graphics2D brush = (Graphics2D) g;
        byte[][] b=board.getBoard();
        for(int i=0;i<8;i++)
        {
            for(int j=0;j<8;j++)
            {
                if(col=!col)
                    brush.setColor(java.awt.Color.black);
                else
                    brush.setColor(java.awt.Color.red);
                g.fillRect(j*w,i*w,w,w);
                
                if (b[i][j]==1)
                {
                    brush.setColor(new java.awt.Color(64,64,64));
                    g.fillOval(j*w+d/2,i*w+d/2,w-d,w-d);
                    brush.setColor(new java.awt.Color(100,100,100));
                    g.drawOval(j*w+d/2,i*w+d/2,w-d,w-d);
                }
                else if (b[i][j]==2)
                {
                    brush.setColor(new java.awt.Color(150,0,0));
                    g.fillOval(j*w+d/2,i*w+d/2,w-d,w-d);
                    brush.setColor(new java.awt.Color(100,0,0));
                    g.drawOval(j*w+d/2,i*w+d/2,w-d,w-d);
                }
                else if (b[i][j]==4)
                {
                    brush.setColor(new java.awt.Color(64,64,64));
                    g.fillOval(j*w+d/2,i*w+d/2,w-d,w-d);
                    brush.setColor(new java.awt.Color(255,255,255));
                    g.drawOval(j*w+d/2,i*w+d/2,w-d,w-d);
                }
                else if (b[i][j]==5)
                {
                    brush.setColor(new java.awt.Color(150,0,0));
                    g.fillOval(j*w+d/2,i*w+d/2,w-d,w-d);
                    brush.setColor(new java.awt.Color(255,255,255));
                    g.drawOval(j*w+d/2,i*w+d/2,w-d,w-d);
                }
                brush.setColor(java.awt.Color.black);
                g.drawString(""+j,j*w+w/2,8*w+w/2);
            }
            brush.setColor(java.awt.Color.black);
            g.drawString(""+i,8*w+w/2,i*w+w/2);
            col=!col;
        }
    }
    
    /**
     *  Evolution
     */
    public void run() 
    {
        if(singleGame)
        {
            while(!endProgram)
            {
                System.out.println("--Game: "+gameNum);
                
                while(!gameOver && moves<moveLimit)
                {
                    if(board.getPlayer()==1)
                    {
                        if(gameNum%2==0)
                            ai(seed);
                        else
                            ai(seed2);
                    }
                    else
                    {
                        if(gameNum%2==0)
                            ai(seed2);
                        else
                            ai(seed);
                    }
                    moves++;
                }
                if(moves>=moveLimit) //draw due to infinite loop
                {
//                    System.out.println("Draw.");
                    draws++;

                    if(scoreDraws) //add wins based on piece count if draw
                    {
                        byte b0[]=board.getByteBoard();
                        int diff=0,reds=0,blacks=0;
                        for (int i=1; i<=35; i++)
                        {
                            if(b0[i]==1)
                                reds+=1;
                            else if (b0[i]==4)
                                reds+=3;
                            else if (b0[i]==2)
                                blacks+=1;
                            else if (b0[i]==5)
                                blacks+=3;
                        }
                        if(gameNum%2==0)//top player is p1
                        {
                            if(reds>blacks)
                            {
                                p1Wins++;
                            }
                            else if (blacks>reds)
                            {
                                p2Wins++;
                            }
                        }
                        else
                        {
                            if(reds>blacks)
                            {
                                p2Wins++;
                            }
                            else if (blacks>reds)
                            {
                                p1Wins++;
                            }
                        }
                    }
                }
                else
                {
                    if(board.getPlayer()==1)
                    {
                        if(gameNum%2==0)
                        {
                            p2Wins++;
                        }
                        else
                        {
                            p1Wins++;
                        }
                    }
                    else
                    {
                        if(gameNum%2==0)
                        {
                            p1Wins++;
                        }
                        else
                        {
                            p2Wins++;
                        }
                    }
                }
                
                System.out.println("P1 wins = "+p1Wins+"\nP2 wins = "+p2Wins+"\nDraws = "+draws);
                
                resetBoard();
                gameOver=false;
                gameNum++;
            }
        }
        else //tournament continuous
        {
            while (!endProgram && generation <= MAXGEN)
            {
                System.out.println("\n---- Generation = "+generation+" ----");
    
                for(int i=0;i<gp.size();i++)
                {
                    if(endProgram)
                        break;
                    for(int j=i;j<gp.size();j++)
                    {
                        for(int k=0;k<numRounds;k++)
                        {
                            if(endProgram)
                                break;
                            if(i!=j)
                            {
                                if(!GUI)
                                    System.out.print("."); //represents 1 game played
        //                        try {Thread.currentThread().sleep(1000);} catch(Exception e) {}
                                
                                if(Math.random()<0.5) //randomize who goes first
                                {
                                    p1=i;
                                    p2=j;
                                }
                                else
                                {
                                    p1=j;
                                    p2=i;
                                }
        /*                        
                                System.out.println();
                                System.out.println("----NEW GAME----");
                                System.out.println(gp.stats(p1));
                                System.out.println("     - VS -     ");
                                System.out.println(gp.stats(p2));
        */
                                while(!gameOver && moves<moveLimit)
                                {
                                    if(board.getPlayer()==1)
                                    {
                                        ai(gp.getPoly(p1));
                                    }
                                    else
                                    {
                                        ai(gp.getPoly(p2));
                                    }
                                    moves++;
                                }
                                if(moves>=moveLimit) //draw due to infinite loop
                                {
        //                            System.out.println("Draw.");
                                    gp.addDraw(p1);
                                    gp.addDraw(p2);
                                }
                                else
                                {
                                    if(board.getPlayer()==1)
                                    {
        //                                System.out.println("White Wins.");
                                        gp.addWin(p2);
                                        gp.addLoss(p1);
                                    }
                                    else
                                    {
        //                                System.out.println("Black Wins.");
                                        gp.addWin(p1);
                                        gp.addLoss(p2);
                                    }
                                }
                                
                                resetBoard();
                                gameOver=false;
                            }
                        }
                    }
                }
                if(!endProgram)
                {
        //            endProgram=true;
                    System.out.println( gp.massExtinction() ); //meteor/plague/etc...
        
                    generation++;
                }
            }
            
        }
        System.out.println("\nProgram Terminated.\nResult:\nGeneration = "+generation+"\nDNA:\n"+gp.allStats());
    }
//              randomAI();
    
    /** Network Functionality **/
    public void contactServer(String opponent) {
        try {
            // connect and set up i/o streams
            sock = new Socket(server, port);
            sockOut = new PrintWriter(sock.getOutputStream(), true);
            sockIn = new BufferedReader(new InputStreamReader(sock.getInputStream()));
            
            // authenticate with user1/pass1
            System.out.println("host: " + sockIn.readLine());   // start message
            System.out.println("host: " + sockIn.readLine());   // id query
            writeMessageAndEcho(user1);                         // send user1 id
            
            System.out.println("host: " + sockIn.readLine());   // password query           
            writeMessage(pass1);                                // send password
            
            System.out.println("host: " + sockIn.readLine());   // opponent query       
            writeMessageAndEcho(opponent);                      // send opponent id
            
            String gameInfo = sockIn.readLine();                // game id
            String playerInfo = sockIn.readLine();              // white or black
            
            System.out.println(gameInfo+"\n"+playerInfo);
            
            //board.printBoard();
            
            if (playerInfo.substring(6, 11).equals("Black")) {
                player = 1; // We are black which is our red
                
                
                // Consume move prompt
                System.out.println( sockIn.readLine() );
                Move m = Stratagem.getBestMove(board, AIDEPTH, -9999, 9999, seed);
                
                // Update board
                executeMove( "AI", m );
                //System.out.println( "------------AI MOVE---------------" );
                //board.printBoard();
                
                // Send move to server
                sendMove( m );
                
                // Consume move echo
                System.out.println( sockIn.readLine() );
            }
            else {
                player = 2; // White is our black
                
                String msg = sockIn.readLine();
                System.out.println( msg );
                
                Move m = parseOpponentMove( msg );
                executeMove( "Opponent", m );
            }
            
            
            
            String msg; 
            while ( true ) {
                
                msg = sockIn.readLine();
                if ( isMovePrompt( msg ) ) {
                    
                    System.out.println( msg );
                    Move m = Stratagem.getBestMove(board, AIDEPTH, -9999, 9999, seed);
                    
                    // Update board
                    executeMove( "AI", m );
                    //System.out.println( "------------AI MOVE---------------" );
                    //board.printBoard();
                    
                    // Send move to server
                    sendMove( m );
                    
                    // Consume move echo
                    System.out.println( sockIn.readLine() );
                }
                else {
                    
                    System.out.println( msg );
                    
                    
                    Move m = parseOpponentMove( msg );
                    if ( m != null ) {
                        
                        // Update board
                        executeMove( "Opponent", m );
                        //System.out.println( "------------OPP MOVE---------------" );
                        //board.printBoard();
                    }
                    else {
                        
                        // Error or result of game
                        // Exit
                        //System.out.println( msg );
                        break;
                    }
                }
            }           
        } catch (UnknownHostException e) {
            System.out.println("Unknown host: " + server);
            System.exit(1);
        } catch (IOException e) {
            System.out.println("No I/O");
            System.exit(1);
        }
    }
    
    public void writeMessage(String msg) {
        sockOut.print(msg+"\r\n");
        sockOut.flush();
    }
    public void writeMessageAndEcho(String msg) {
        sockOut.print(msg+"\r\n");
        sockOut.flush();
        System.out.println("  me: "+msg);
    }
    
    /**
     * Detects if the given message is an opponent move.
     * If it is, a Move is returned.
     */
    private Move parseOpponentMove( String msg ) {
        
        if ( msg.substring(0, 4).equals("Move") ) {
            
            StringTokenizer tokens = new StringTokenizer( msg, ":" );
            
            // Consume first two tokens, they are not part of the actual moves
            tokens.nextToken();
            tokens.nextToken();
            
            Move m = new Move();
            while ( tokens.hasMoreTokens() ) {
                
                int row = Integer.parseInt( tokens.nextToken().substring( 1, 2 ) );
                int col = Integer.parseInt( tokens.nextToken().substring( 0, 1 ) );
                
                m.addCoord( convertServerToClientCoord( row, col ) );
            }
            
            return m;
        }
        
        return null;    
    }
    
    /**
     * Detects if the given message is a move prompt. If true,
     * the time left is updated.
     */
    private boolean isMovePrompt( String msg ) {
        
        if ( msg.substring(0, 5).equals("?Move") ) {
            
            // TODO: Update the amount of remaining time
            
            return true;
        }
        return false;
    }
    
    
    private Coord convertClientToServerCoord( int x, int y ) {
        
        return new Coord( 7 - x, y );
    }
    
    private Coord convertServerToClientCoord( int row, int col ) {
        
        return new Coord( 7 - row, col );
    }
    
    
    
    public void sendMove(Move move) {
        
        StringBuilder serverMove = new StringBuilder();
        
        int max = move.size();
        for ( int i = 0; i < max; ++i ) {
            
            Coord temp = move.get( i );
            Coord c = convertClientToServerCoord( temp.x, temp.y );
            
            serverMove.append( "(" + c.x + ":" + c.y + "):" );
        }
        
        // Send the move
        System.out.println("TO: " + serverMove.substring(0, serverMove.length() - 1 ) );
        writeMessage( serverMove.substring(0, serverMove.length() - 1 ) );
    }
}